#ifndef CMD_DIST_H
#define CMD_DIST_H

#include "com.h"
#include <functional>

#define BIND_FUNCTION(function) std::bind(function, this, std::placeholders::_1)

using CmdHandle = std::function<int(int)>;

typedef struct {
    CmdHandle handle;
    string help;
} CmdHandler;

vector<string> Split(const string &s, char delimiter) {
    vector<string> tokens;
    string token;
    std::istringstream tokenStream(s);
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

class CmdDist {
public:
    int ExeCmd(string cmdStr)
    {
        if (cmdStr.empty()) {
            return -1;
        }

        vector<string> cmdParts = Split(cmdStr, ',');
        if (cmdParts.size() != 2) {
            cout << "wrong cmd: " << cmdStr << endl;
            return -1;
        }

        string cmdKey = cmdParts[0];

        map<string, CmdHandler> *cmds = GetCmds();
        if (cmds->find(cmdKey) == cmds->end()) {
            cout << "cmd[" << cmdKey << "] not found!" << endl;
            cout << "usage:" << endl;
            for (auto cmd : *cmds) {
                cout << "  " << cmd.second.help << endl;
            }
            return -1;
        }

        CmdHandle handle = (*cmds)[cmdKey].handle;
        int para = std::stoi(cmdParts[1]);
        return handle(para);
    }

protected:
    CmdDist(string module) : m_module(module) {}

private:
    virtual map<string, CmdHandler> *GetCmds() = 0;

protected:
    string m_module;
};

#endif
